// 缓存项接口
export interface CacheItem<T> {
  value: Promise<T>;
  // null表示永不过期
  expireTime: number | null;
}

// 缓存配置选项
export interface CacheOptions {
  /** 缓存有效期（毫秒），null表示永不过期 */
  expireTime?: number | null;
}

class RequestCache {
  private cache: Map<string | number | symbol, CacheItem<any>> = new Map();
  private defaultExpireTime: number | null = 5 * 60 * 1000; // 默认5分钟
  private cleanupTimer: number | null | NodeJS.Timeout = null;
  private nextCleanupTime: number | null = null;
  private readonly CLEANUP_INTERVAL = 60 * 1000; // 一分钟检查一次

  constructor(defaultExpireTime?: number | null) {
    if (defaultExpireTime !== undefined) {
      this.defaultExpireTime = defaultExpireTime;
    }
  }

  /**
   * 设置默认缓存有效期
   * @param expireTime 缓存有效期（毫秒），null表示永不过期
   */
  setDefaultExpireTime(expireTime: number | null): void {
    this.defaultExpireTime = expireTime;
  }

  /**
   * 获取缓存项
   * @param key 缓存键
   * @returns 缓存值或undefined（如果不存在）
   */
  get<T>(key: string | number | symbol): Promise<T> | undefined {
    const item = this.cache.get(key);

    if (!item) {
      return undefined;
    }

    // 检查是否过期
    if (item.expireTime !== null && Date.now() > item.expireTime) {
      this.cache.delete(key);
      return undefined;
    }

    return item.value;
  }

  /**
   * 设置缓存项
   * @param key 缓存键
   * @param value 缓存值
   * @param options 缓存选项
   */
  set<T>(key: string | number | symbol, value: Promise<T>, options?: CacheOptions): void {
    const expireTime = options?.expireTime !== undefined ? options.expireTime : this.defaultExpireTime;

    const item: CacheItem<T> = {
      value,
      expireTime: expireTime === null ? null : Date.now() + expireTime
    };

    // 如果已经过期，直接返回
    if (item.expireTime !== null && item.expireTime <= Date.now()) {
      return;
    }

    this.cache.set(key, item);

    // 如果设置了过期时间，计划清理
    if (item.expireTime !== null) {
      this.scheduleNextCleanup(item.expireTime);
    }
  }

  /**
   * 删除缓存项
   * @param key 缓存键
   */
  delete(key: string | number | symbol): boolean {
    return this.cache.delete(key);
  }

  /**
   * 清空所有缓存
   */
  clear(): void {
    this.cache.clear();
    this.cancelCleanup();
  }

  /**
   * 检查键是否存在且未过期
   * @param key 缓存键
   */
  has(key: string | number | symbol): boolean {
    const item = this.cache.get(key);

    if (!item) {
      return false;
    }

    // 检查是否过期
    if (item.expireTime !== null && Date.now() > item.expireTime) {
      this.cache.delete(key);
      return false;
    }

    return true;
  }

  /**
   * 计划下一次清理
   * @param nextExpireTime 下一个过期时间
   */
  private scheduleNextCleanup(nextExpireTime: number): void {
    // 如果已经安排了更早的清理，不做任何事情
    if (this.nextCleanupTime !== null && this.nextCleanupTime <= nextExpireTime) {
      return;
    }

    // 取消现有的计划
    this.cancelCleanup();

    // 设置新的清理时间（最多CLEANUP_INTERVAL后执行）
    const delay = Math.min(nextExpireTime - Date.now(), this.CLEANUP_INTERVAL);
    this.nextCleanupTime = Date.now() + delay;

    this.cleanupTimer = setTimeout(() => {
      this.cleanupExpired();
    }, delay);
  }

  /**
   * 取消计划的清理
   */
  private cancelCleanup(): void {
    if (this.cleanupTimer !== null) {
      clearTimeout(this.cleanupTimer);
      this.cleanupTimer = null;
      this.nextCleanupTime = null;
    }
  }

  /**
   * 清理过期的缓存项
   */
  private cleanupExpired(): void {
    this.cleanupTimer = null;
    this.nextCleanupTime = null;

    const now = Date.now();
    let nextExpireTime: number | null = null;

    // 清理过期项并找到下一个过期时间
    for (const [key, item] of this.cache.entries()) {
      if (item.expireTime !== null) {
        if (item.expireTime <= now) {
          // 过期项删除
          this.cache.delete(key);
        } else if (nextExpireTime === null || item.expireTime < nextExpireTime) {
          // 记录最近的过期时间
          nextExpireTime = item.expireTime;
        }
      }
    }

    // 如果还有项目将过期，安排下一次清理
    if (nextExpireTime !== null) {
      this.scheduleNextCleanup(nextExpireTime);
    }
  }
}

const requestCache = new RequestCache();
export default requestCache;
